#include "Mesh.h"
#include "DDSTextureLoader11.h"

static void ParseEle(const string& src, std::vector<string>& dst)
{
	dst.clear();
	if (src.length() == 0)
	{
		return;
	}
	//commment
	if (src[0] == '#')
	{
		dst.push_back("#");
		dst.push_back(src.substr(1, src.length() - 1));
		return;
	}
	for (int start = 0, i = 0; i <= src.length(); i++)
	{
		if (i == src.length())
		{
			if (i > start)
			{
				dst.push_back(src.substr(start, i - start));
			}
		}
		if (src[i] == ' ') {
			if (i > start) {
				dst.push_back(src.substr(start, i - start));
			}
			start = i + 1;
		}
	}
	return;
}
static void ParseSubEle(const string& src, std::vector<string>& dst)
{

}

bool LoadObjModel(vector<Vertex> &vertexes, vector<int>& posId)
{
	const string objFilePath = "L2.obj";
	bool RightHand = true;
	bool HasTexture = false;
	bool HasMaterial = false;
	bool HasNormal = false;

	string line;
	ifstream objFileStream(objFilePath);
	if (!objFileStream.is_open())
	{
		MessageBoxA(0, "error when open obj file!", 0, 0);
		return false;
	}
	bool err = false;
	vector<string> tokens;
	vector<XMFLOAT3> vertexPos;
	vector<XMFLOAT3> vertexNormal;
	vector<XMFLOAT2> vertexTexCoord;
	vector<int> texCoordId, normalId;
	map<int, vector<int>> sharedFace;
	string mtllibFilePath;
	int posNum = 0;
	int normalNum = 0;
	int texCoordNum = 0;
	int submeshTriangleNum = 0;
	map<int, int> vId2TexCoordId;
	map<int, int> vId2NormalId;
	map<int, bool> alreadyLoadv;
	do
	{
		if (objFileStream.eof())
		{
			break;
		}
		getline(objFileStream, line);
		if (!line.length()) continue;
		ParseEle(line, tokens);
		if (tokens[0] == "#")
		{
			continue;
		}
		else if (tokens[0] == "mtllib")
		{
			if (tokens.size() != 2) 
			{
				err = true;
				break;
			}
			mtllibFilePath = tokens[1];
			HasMaterial = true;
		}
		else if (tokens[0] == "o")
		{

		}
		else if (tokens[0] == "v")
		{
			float vx, vy, vz;
			if (tokens.size() != 4)
			{
				err = true;
				break;
			}
			sscanf_s(tokens[1].c_str(), "%f", &vx);
			sscanf_s(tokens[2].c_str(), "%f", &vy);
			sscanf_s(tokens[3].c_str(), "%f", &vz);
			if (RightHand) vz *= -1.0f;
			vertexPos.push_back(XMFLOAT3(vx, vy, vz));
			posNum++;
		}
		else if (tokens[0] == "vt")
		{
			float u, v;
			if (tokens.size() != 3)
			{
				err = true;
				break;
			}
			sscanf_s(tokens[1].c_str(), "%f", &u);
			sscanf_s(tokens[2].c_str(), "%f", &v);
			if (RightHand) v *= 1.0f - v;
			vertexTexCoord.push_back(XMFLOAT2(u, v));
			texCoordNum++;
			HasTexture = true;
		}
		else if (tokens[0] == "vn")
		{
			float x, y, z;
			if (tokens.size() != 4)
			{
				err = true;
				break;
			}
			sscanf_s(tokens[1].c_str(), "%f", &x);
			sscanf_s(tokens[2].c_str(), "%f", &y);
			sscanf_s(tokens[3].c_str(), "%f", &z);
			if (RightHand) z *= -1.0f;
			vertexNormal.push_back(XMFLOAT3(x, y, z));
			normalNum++;
			HasNormal = true;
		}
		else if (tokens[0] == "usemtl")
		{
			if (!HasMaterial)
			{
				err = true;
				break;
			}
		}
		else if (tokens[0] == "s")
		{

		}
		else if (tokens[0] == "f")
		{
			//f id1 id2 id3 ...
			//f id/tex/normal1 id/tex/normal2 id/tex/normal3 ...
			//f id//normal1 id//normal2 id//normal3 ...
			//f id/tex1 id/tex2 id/tex3 ...
			int triangleNum = tokens.size() - 3;
			if (triangleNum < 1)
			{
				err = true;
				break;
			}
			int pos1 = tokens[1].find_first_of('/');
			int pos2 = tokens[1].find_last_of('/');
			if (pos1 == string::npos)
			{
				int id1, id2, id3;
				sscanf_s(tokens[1].c_str(), "%d", &id1);
				sscanf_s(tokens[2].c_str(), "%d", &id2);
				for (int j = 0; j < triangleNum; j++)
				{
					sscanf_s(tokens[j + 3].c_str(), "%d", &id3);
					posId.push_back(id1 - 1);
					posId.push_back(id2 - 1);
					posId.push_back(id3 - 1);
					if (sharedFace.count(id1 - 1))
						sharedFace[id1 - 1].push_back(submeshTriangleNum + j);
					else
						sharedFace[id1 - 1] = vector<int>({ submeshTriangleNum + j });
					if (sharedFace.count(id1 - 1))
						sharedFace[id2 - 1].push_back(submeshTriangleNum + j);
					else
						sharedFace[id2 - 1] = vector<int>({ submeshTriangleNum + j });
					if (sharedFace.count(id1 - 1))
						sharedFace[id3 - 1].push_back(submeshTriangleNum + j);
					else
						sharedFace[id3 - 1] = vector<int>({ submeshTriangleNum + j });
					id2 = id3;
				}
				submeshTriangleNum += triangleNum;
			}
			else if (pos1 == pos2)
			{
				int id1, id2, id3;
				int texCoord1, texCoord2, texCoord3;
				sscanf_s(tokens[1].c_str(), "%d/%d", &id1, &texCoord1);
				sscanf_s(tokens[2].c_str(), "%d/%d", &id2, &texCoord2);
				if (!vId2TexCoordId.count(id1-1))vId2TexCoordId[id1-1] = texCoord1 - 1;
				if (!vId2TexCoordId.count(id2-1))vId2TexCoordId[id2-1] = texCoord2 - 1;
				for (int j = 0; j < triangleNum; j++)
				{
					sscanf_s(tokens[j+3].c_str(), "%d/%d", &id3, &texCoord3);
					if (!vId2TexCoordId.count(id3-1))vId2TexCoordId[id3-1] = texCoord3 - 1;
					posId.push_back(id1 - 1);
					posId.push_back(id2 - 1);
					posId.push_back(id3 - 1);
					if (sharedFace.count(id1 - 1))
						sharedFace[id1 - 1].push_back(submeshTriangleNum + j);
					else
						sharedFace[id1 - 1] = vector<int>({ submeshTriangleNum + j });
					if (sharedFace.count(id1 - 1))
						sharedFace[id2 - 1].push_back(submeshTriangleNum + j);
					else
						sharedFace[id2 - 1] = vector<int>({ submeshTriangleNum + j });
					if (sharedFace.count(id1 - 1))
						sharedFace[id3 - 1].push_back(submeshTriangleNum + j);
					else
						sharedFace[id3 - 1] = vector<int>({ submeshTriangleNum + j });
					id2 = id3;
				}
				submeshTriangleNum += triangleNum;
			}
			else if (pos2 - pos1 == 1)
			{
				int id1, id2, id3;
				int normal1, normal2, normal3;
				sscanf_s(tokens[1].c_str(), "%d//%d", &id1, &normal1);
				sscanf_s(tokens[2].c_str(), "%d//%d", &id2, &normal2);
				if (!vId2NormalId.count(id1-1))vId2TexCoordId[id1 - 1] = normal1 - 1;
				if (!vId2NormalId.count(id2-1))vId2TexCoordId[id2 - 1] = normal2 - 1;
				for (int j = 0; j < triangleNum; j++)
				{
					sscanf_s(tokens[j + 3].c_str(), "%d//%d", &id3, &normal3);
					if (!vId2NormalId.count(id3-1))vId2NormalId[id3-1] = normal3 - 1;
					posId.push_back(id1 - 1);
					posId.push_back(id2 - 1);
					posId.push_back(id3 - 1);
					if (sharedFace.count(id1 - 1))
						sharedFace[id1 - 1].push_back(submeshTriangleNum + j);
					else
						sharedFace[id1 - 1] = vector<int>({ submeshTriangleNum + j });
					if (sharedFace.count(id1 - 1))
						sharedFace[id2 - 1].push_back(submeshTriangleNum + j);
					else
						sharedFace[id2 - 1] = vector<int>({ submeshTriangleNum + j });
					if (sharedFace.count(id1 - 1))
						sharedFace[id3 - 1].push_back(submeshTriangleNum + j);
					else
						sharedFace[id3 - 1] = vector<int>({ submeshTriangleNum + j });
					id2 = id3;
				}
				submeshTriangleNum += triangleNum;
			}
			else
			{
				int id1, id2, id3;
				int texCoord1, texCoord2, texCoord3;
				int normal1, normal2, normal3;
				sscanf_s(tokens[1].c_str(), "%d/%d/%d", &id1, &texCoord1, &normal1);
				sscanf_s(tokens[2].c_str(), "%d/%d/%d", &id2, &texCoord2, &normal2);
				if (!vId2NormalId.count(id1 - 1))vId2TexCoordId[id1 - 1] = normal1 - 1;
				if (!vId2NormalId.count(id2 - 1))vId2TexCoordId[id2 - 1] = normal2 - 1;
				if (!vId2TexCoordId.count(id1 - 1))vId2TexCoordId[id1 - 1] = texCoord1 - 1;
				if (!vId2TexCoordId.count(id2 - 1))vId2TexCoordId[id2 - 1] = texCoord2 - 1;
				for (int j = 0; j < triangleNum; j++)
				{
					sscanf_s(tokens[j + 3].c_str(), "%d/%d/%d", &id3, &texCoord3, &normal3);
					if (!vId2TexCoordId.count(id3 - 1))vId2TexCoordId[id3 - 1] = texCoord3 - 1;
					if (!vId2NormalId.count(id3 - 1))vId2NormalId[id3 - 1] = normal3 - 1;
					posId.push_back(id1 - 1);
					posId.push_back(id2 - 1);
					posId.push_back(id3 - 1);
					if (sharedFace.count(id1 - 1))
						sharedFace[id1 - 1].push_back(submeshTriangleNum + j);
					else
						sharedFace[id1 - 1] = vector<int>({ submeshTriangleNum + j });
					if (sharedFace.count(id1 - 1))
						sharedFace[id2 - 1].push_back(submeshTriangleNum + j);
					else
						sharedFace[id2 - 1] = vector<int>({ submeshTriangleNum + j });
					if (sharedFace.count(id1 - 1))
						sharedFace[id3 - 1].push_back(submeshTriangleNum + j);
					else
						sharedFace[id3 - 1] = vector<int>({ submeshTriangleNum + j });
					id2 = id3;
				}
				submeshTriangleNum += triangleNum;
			}
		}
		else if (tokens[0] == "g")
		{

		}
		else 
		{
			err = true;
			break;
		}
	} while (true);
	if (err)
	{
		MessageBoxA(0, "obj file format error!", 0, 0);
		MessageBoxA(0, line.c_str(), 0, 0);
		return false;
	}
	Vertex tempv;
	//MessageBoxA(0, "reach here!", 0, 0);
	for (int i = 0; i < posNum; i++)
	{
		if (i > 7651)
		{
			i = i;
		}
		int sharedFaceNum = sharedFace[i].size();
		float vecX, vecY, vecZ;
		XMFLOAT3 vecNormal = XMFLOAT3(0.0f, 0.0f, 0.0f);

		tempv.pos = vertexPos[i];
		if (HasTexture) {
			if (vId2TexCoordId.count(i))
			{
				int texcoord_key = vId2TexCoordId[i];
				if (texcoord_key < vertexTexCoord.size())
					tempv.texCoord = vertexTexCoord[texcoord_key];
			}
		}
		else tempv.texCoord = XMFLOAT2(0.0f, 0.0f);
		if (HasNormal) {
			if (vId2NormalId.count(i))
			{
				int normal_key = vId2NormalId[i];
				if (normal_key < vertexNormal.size())
					tempv.normal = vertexNormal[normal_key];
			}
		}
		else 
		{
			for (int k = 0; k < sharedFaceNum; k++)
			{
				XMFLOAT3 tempNormal;
				XMVECTOR edge_u, edge_v;

				int j = sharedFace[i][k];
				vecX = vertexPos[posId[3 * j]].x - vertexPos[posId[3 * j + 2]].x;
				vecY = vertexPos[posId[3 * j]].y - vertexPos[posId[3 * j + 2]].y;
				vecZ = vertexPos[posId[3 * j]].z - vertexPos[posId[3 * j + 2]].z;
				edge_u = XMVectorSet(vecX, vecY, vecZ, 0.0f);

				vecX = vertexPos[posId[3 * j + 2]].x - vertexPos[posId[3 * j + 1]].x;
				vecY = vertexPos[posId[3 * j + 2]].y - vertexPos[posId[3 * j + 1]].y;
				vecZ = vertexPos[posId[3 * j + 2]].z - vertexPos[posId[3 * j + 1]].z;
				edge_v = XMVectorSet(vecX, vecY, vecZ, 0.0f);

				XMStoreFloat3(&tempNormal, XMVector3Cross(edge_u, edge_v));
				vecNormal.x = vecNormal.x + tempNormal.x;
				vecNormal.y = vecNormal.y + tempNormal.y;
				vecNormal.z = vecNormal.z + tempNormal.z;
			}
		}
		if (!HasNormal&&sharedFaceNum)
		{
			vecNormal.x /= sharedFaceNum;
			vecNormal.y /= sharedFaceNum;
			vecNormal.z /= sharedFaceNum;
			tempv.normal = vecNormal;
		}
		vertexes.push_back(tempv);
	}
	//vertexes[0].normal = XMFLOAT3(-1.0f, -1.0f, -1.0f);
	//vertexes[1].normal = XMFLOAT3(1.0f, -1.0f, -1.0f);
	//vertexes[2].normal = XMFLOAT3(1.0f, -1.0f, 1.0f);
	//vertexes[3].normal = XMFLOAT3(-1.0f, -1.0f, 1.0f);
	//vertexes[4].normal = XMFLOAT3(-1.0f, 1.0f, -1.0f);
	//vertexes[5].normal = XMFLOAT3(1.0f, 1.0f, -1.0f);
	//vertexes[6].normal = XMFLOAT3(1.0f, 1.0f, 1.0f);
	//vertexes[7].normal = XMFLOAT3(-1.0f, 1.0f, 1.0f);
	return true;
}